
//indexdb 对indexdb的封装，主要添加以下功能
//1、写入数据时，防止indexdb超出存储上限崩溃
//2、全局indexdb规范，必须先在storageList声明，才能使用，不能随意使用

//3、规范会在每次set的时候校验
const storageList = [
    'zhiliao_live_sticker', //之了课堂直播表情包_partid
    'zhiliao_live_chatmessage_$_$' //之了课堂聊天记录_liveid_partid
]

//t_zhiliao_file结构为：
//file_key:string 文件唯一标识
//version：string|int 版本号，不匹配会重新下载
//file:string 文件内容值
//create_time:int 创建时间戳
//persist：int 是否永久持续化 0|1
let zlFileDb = {
    dbName: 'db_zhiliao',
    tableName: 't_zhiliao_file',
    dbVersion: 1,
    isLogger: true,
    //fileInfo对象如下:
    /*{
        fileKey:string  文件的key
        url:string 为下载地址
        version：string|int 版本号，不匹配会重新下载
        versionCompareCb:function(oldVersion, newVersion) { return true|false} 返回true，表示当缓存存在则使用缓存；返回false，表示当缓存存在但版本需要更新，则不使用缓存
        callback:function(isSuccess,value) {}  isSuccess: 0|1成功失败，value；isSuccess为1，表示文件内容；isSuccess为0，表示失败消息
        persist:true|false是否永久持续化 对于聊天表情文件，建议配置1；直播聊天文件建议使用0
    }
    
    调用方法：
    var version = '20220402'
    window.zlFileDb.getFileStorage(
        {
            fileKey:'zhiliao_live_sticker',
            version:version,
            url:'//shenji.zlketang.com/public/20220401.txt',
            versionCompareCb:function(oldVersion,newVersion) {if (oldVersion != newVersion) return false; return true;},
            callback:function(isSuccess,value) {}
        }
    )
    */
    getFileStorage(fileInfo) {
        var fileKey = fileInfo.fileKey
        var version = fileInfo.version
        var versionCompareCb =
            typeof fileInfo.versionCompareCb === 'function'
                ? fileInfo.versionCompareCb
                : null
        var callback =
            typeof fileInfo.callback === 'function' ? fileInfo.callback : null
        var persist = fileInfo.persist ? 1 : 0
        var url = fileInfo.url

        var downloadCallback = function (dbReq, isSuccess, value) {
            if (!isSuccess) {
                callback(false, value ? value : '加载失败')
                return
            }
            if (dbReq) {
                //当没有异常情况下，增加文件缓存记录
                try {
                    var objectStore = dbReq
                        .transaction(zlFileDb.tableName, 'readwrite')
                        .objectStore(zlFileDb.tableName)
                    objectStore.add({
                        file_key: fileKey,
                        version: version,
                        file: value,
                        create_time: new Date().getTime(),
                        persist: persist
                    })
                } catch (e) {
                    //异常，打印日志
                    zlFileDb.isLogger && console.error(e)
                }
            }
            callback && callback(true, value)
        }

        var indexedDB =
            window.indexedDB ||
            window.mozIndexedDB ||
            window.webkitIndexedDB ||
            window.msIndexedDB
        if (!indexedDB) {
            //不存在对象，直接下载返回
            zlFileDb.downloadFile(
                null,
                url,
                downloadCallback,
                zlFileDb.dbVersion
            )
            zlFileDb.isLogger && console.error('indexedDB is not exist')
            return
        }
        var dbRequest = indexedDB.open(
            zlFileDb.dbName,
            zlFileDb.dbVersion
        ) //默认为1，当未来升级，可以设置为N+1，在onupgradeneeded执行升级操作即可
        dbRequest.onupgradeneeded = zlFileDb.onupgradeneeded

        dbRequest.onerror = function (dbEvent) {
            //数据库加载失败，直接下载
            zlFileDb.isLogger && console.error('dbEvent falied', dbEvent)
            zlFileDb.downloadFile(null, url, downloadCallback, 1)
        }

        dbRequest.onsuccess = function (dbEvent) {
            //数据加载成功，直接下载
            var dbReq = dbEvent.target.result
            var objectStore = null
            try {
                objectStore = dbReq
                    .transaction(zlFileDb.tableName, 'readwrite')
                    .objectStore(zlFileDb.tableName)
            } catch (e) {
                //不存在或者不匹配版本，重新下载
                zlFileDb.isLogger && console.error('transaction falied', e)
                zlFileDb.downloadFile(null, url, downloadCallback, 1)
                return
            }
            var tableRequest = objectStore.get(fileKey)

            tableRequest.onerror = function (tableEvent) {
                //读取表成功失败，直接下载
                zlFileDb.isLogger &&
                    console.error('tableEvent falied', tableEvent)
                zlFileDb.downloadFile(null, url, downloadCallback, 1)
            }

            tableRequest.onsuccess = function (tableEvent) {
                //读取表成功
                var tableResult = tableEvent.target.result
                zlFileDb.isLogger && console.warn('tableResult success')
                if (tableResult) {
                    if (versionCompareCb) {
                        //判断为真，即使用缓存
                        if (versionCompareCb(tableResult.version, version)) {
                            //判断为真，即使用缓存
                            callback(true, tableResult.file)
                            return
                        } else {
                            objectStore.delete(fileKey)
                            return
                        }
                    } else if (tableResult.version === version) {
                        //版本不匹配
                        callback(true, tableResult.file)
                        return
                    } else {
                        objectStore.delete(fileKey)
                    }
                }
                //不存在或者不匹配版本，重新下载
                zlFileDb.downloadFile(dbReq, url, downloadCallback, 1)
            }
        }
    },
    onupgradeneeded(dbEvent) {
        zlFileDb.isLogger && console.warn('dbEvent success', dbEvent)
        var dbReq = dbEvent.target.result
        if (!dbReq.objectStoreNames.contains(zlFileDb.tableName)) {
            //检测文件是否存在，不存在，则创建文件
            dbReq.createObjectStore(zlFileDb.tableName, {
                keyPath: 'file_key'
            })
        }
    },
    downloadFile(dbReq, url, downloadCallback, retry) {
        //下载文件
        var xhr = new XMLHttpRequest()
        xhr.open('GET', url, true)
        xhr.timeout = 6000
        retry--
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    // 请求成功
                    downloadCallback(dbReq, true, xhr.response)
                } else {
                    // 请求失败
                    downloadCallback(dbReq, false, 'URL请求失败:onreadystatechange')
                }
            }
        }
        xhr.onerror = function (event) {
            if (retry >= 1) {
                //可以重试
                zlFileDb.downloadFile(dbReq, url, downloadCallback, retry)
            } else {
                //请求超时
                downloadCallback(dbReq, false, 'URL请求失败:onerror')
            }
        }
        xhr.ontimeout = function (event) {
            if (retry >= 1) {
                //可以重试
                zlFileDb.downloadFile(dbReq, url, downloadCallback, retry)
            } else {
                //请求超时
                downloadCallback(dbReq, false, 'URL请求超时')
            }
        }
        xhr.send()
    },

    clear(exceptionKeys, maxRemainFiles) {
        exceptionKeys = Array.isArray(exceptionKeys) ? exceptionKeys : []
        maxRemainFiles = maxRemainFiles || 20

        var indexedDB =
            window.indexedDB ||
            window.mozIndexedDB ||
            window.webkitIndexedDB ||
            window.msIndexedDB
        if (!indexedDB) {
            //不存在对象，直接下载返回
            return
        }

        var dbRequest = indexedDB.open(
            zlFileDb.dbName,
            zlFileDb.dbVersion
        )
        dbRequest.onupgradeneeded = zlFileDb.onupgradeneeded

        dbRequest.onsuccess = function (dbEvent) {
            //数据加载成功，直接下载
            var dbReq = dbEvent.target.result
            var objectStore = null

            try {
                objectStore = dbReq
                    .transaction(zlFileDb.tableName, 'readwrite')
                    .objectStore(zlFileDb.tableName)
            } catch (e) {
                zlFileDb.isLogger && console.error('transaction falied', e)
                return
            }
            var fileKeys = []
            objectStore.openCursor().onsuccess = function (event) {
                const cursor = event.target.result
                if (cursor) {
                    if (!cursor.value.persist) {
                        //获取非永久保存的keys
                        if (exceptionKeys && exceptionKeys.indexOf(cursor.key) > -1) {
                            //属于排除在外的key不进行统计
                        } else {
                            fileKeys.push({
                                key: cursor.key,
                                create_time: cursor.value.create_time
                            })
                        }
                    }
                    cursor.continue() // 继续下一个
                } else {
                    if (!fileKeys) return

                    var deleteFileKeys = []
                    var lineTime = new Date().getTime() - 10 * 24 * 3600

                    fileKeys.sort(function (a, b) {
                        return b.create_time - a.create_time
                    }) //降序排列
                    fileKeys.forEach(function (currentValue, index) {
                        //当序列大于最大保留文件数或者10天前的文件
                        if (
                            index > maxRemainFiles ||
                            lineTime > currentValue.create_time
                        ) {
                            deleteFileKeys.push(currentValue.key)
                        }
                    })

                    //删除文件缓存
                    zlFileDb.isLogger &&
                        console.warn(
                            'fileKeys and deleteFileKeys',
                            fileKeys,
                            deleteFileKeys
                        )
                    deleteFileKeys.forEach(function (currentValue, index) {
                        objectStore.delete(currentValue)
                    })
                }
            }
        }
    }
}
export default zlFileDb
